Skip to content

Conversation

@kziemianek
Copy link
Member

@kziemianek kziemianek commented Nov 4, 2025

Upgrade to the OmniAccount smart contract architecture that adds a module system for extensible functionality. This enables users to register custom modules that execute within the account's context via delegatecall, allowing for composable account features.

Module Management System:
- registerModule(address) - Register trusted modules (owner-only)
- unregisterModule(address) - Remove modules (owner-only)
- executeModuleCall(address, bytes) - Execute module logic via delegatecall (EntryPoint-only)
- isModuleRegistered(address) - Check module registration status

Uses delegeateCall so modules execute in account's context (can access account storage).

@kziemianek kziemianek requested a review from a team November 4, 2025 09:51
@linear
Copy link

linear bot commented Nov 4, 2025

@vercel
Copy link

vercel bot commented Nov 4, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Comments Updated (UTC)
heima Ready Ready Preview Comment Nov 27, 2025 8:55pm
1 Skipped Deployment
Project Deployment Preview Comments Updated (UTC)
heima-aa-demo-app Ignored Ignored Preview Nov 27, 2025 8:55pm

@claude
Copy link

claude bot commented Nov 4, 2025

Claude finished @kziemianek's task —— View job


PR Review: OmniAccountV2 with Module System

I've completed a comprehensive review of this PR. Here's my detailed feedback:

Todo List:

  • Read repository guidelines (CLAUDE.md)
  • Analyze core contracts (OmniAccountV2, OmniAccountFactoryV2, LibModuleManager)
  • Review module system security and delegatecall usage
  • Evaluate test coverage and quality
  • Check upgrade mechanisms and V1 compatibility
  • Provide comprehensive feedback and recommendations

🔍 Code Quality Assessment

Overall Quality: Good - The implementation follows established patterns and includes comprehensive testing.

Positive Aspects:

  • Clean Architecture: Well-structured separation between core account logic and module management
  • Comprehensive Testing: Excellent test coverage with 13 new test files covering various scenarios
  • Backward Compatibility: Proper upgrade path from V1 to V2 with state preservation
  • Documentation: Good inline comments and clear function naming

🔒 Security Analysis

HIGH PRIORITY - Critical Security Concerns:

  1. ⚠️ Unrestricted delegatecall Execution (OmniAccountV2.sol:269-279)

    function executeModuleCall(address module, bytes calldata data) external virtual returns (bytes memory) {
        _requireFromEntryPoint();
        require(LibModuleManager.isModuleRegistered(module), "Module not registered");
        
        bool ok = Exec.delegateCall(module, data, gasleft()); // ⚠️ Dangerous

    Issues:

    • Modules can access and modify ALL account storage via delegatecall
    • No restrictions on what functions modules can execute
    • Modules could potentially override critical account functions like _onlyOwner()
    • Missing storage collision protection enforcement
  2. 🚨 Missing Module Validation (LibModuleManager.sol:22-33)

    function registerModule(address module) internal {
        require(module != address(0), "Invalid module address");
        require(!isModuleRegistered(module), "Module already registered");
        
        uint256 codeSize;
        assembly {
            codeSize := extcodesize(module)
        }
        require(codeSize > 0, "Module must be a contract");
        // ⚠️ No validation of module interface or safety

    Missing validations:

    • No interface compliance checking
    • No verification that module follows storage namespace patterns
    • No access control validation within modules

Medium Priority Concerns:

  1. Access Control Inconsistency (OmniAccountV2.sol:244-253)

    • Module functions added to restricted call list but no enforcement mechanism for modules themselves
    • Root signers and session keys can potentially call non-restricted module functions
  2. Storage Collision Risk

    • While StorageTestModule.sol demonstrates proper namespaced storage, there's no enforcement
    • Malicious modules could intentionally corrupt account state

🚀 Performance Considerations

Positive:

  • Efficient storage access pattern in LibModuleManager
  • Gas-optimized delegatecall implementation
  • Minimal storage overhead for module registry

Areas for Optimization:

  • executeModuleCall uses gasleft() which could be optimized with gas limits
  • Multiple storage reads in module validation could be cached

🧪 Test Coverage Analysis

Excellent Coverage (95%+) - Comprehensive test suite with:

Strengths:

  • Module Registration: All edge cases covered (OmniAccountV2Modules.t.sol)
  • Storage Isolation: Excellent test demonstrating delegatecall context (StorageTestModule.sol)
  • Upgrade Testing: Thorough V1→V2 migration tests (OmniAccountV1ToV2Upgrade.t.sol)
  • Actor-based Testing: Separate test files for different user roles

Missing Test Scenarios:

  1. Malicious Module Tests: No tests for modules that intentionally corrupt storage
  2. Reentrancy Tests: Missing tests for module reentrancy attacks
  3. Gas Limit Tests: No tests for module execution gas exhaustion
  4. Module Interface Tests: Missing validation of module return data handling

🔧 Recommendations

Critical (Must Fix):

  1. Implement Module Interface Standard

    interface IModule {
        function moduleId() external pure returns (bytes32);
        function moduleVersion() external pure returns (string memory);
        function storageNamespace() external pure returns (bytes32);
    }
  2. Add Module Safety Validation in LibModuleManager.registerModule():

    // Verify module implements required interface
    require(IModule(module).moduleId() != bytes32(0), "Invalid module interface");
    
    // Verify storage namespace to prevent collisions
    bytes32 namespace = IModule(module).storageNamespace();
    require(namespace != bytes32(0) && namespace != ACCOUNT_STORAGE_NAMESPACE, "Invalid storage namespace");
  3. Implement Function Whitelist for modules:

    mapping(bytes4 => bool) public allowedModuleFunctions;
    
    function executeModuleCall(address module, bytes calldata data) external {
        bytes4 selector = bytes4(data[:4]);
        require(allowedModuleFunctions[selector], "Function not allowed for modules");

Important:

  1. Add Storage Protection: Document and enforce storage slot reservations
  2. Implement Module Timelock: Add delay for module registration changes
  3. Gas Limits: Add configurable gas limits for module execution

Nice to Have:

  1. Module Registry Events: Enhanced events with more metadata
  2. Batch Module Operations: Allow registering multiple modules atomically
  3. Module Dependencies: Support for module dependency management

📋 Minor Issues

  • Line 273 (OmniAccountV2.sol): Consider using try/catch instead of manual revert checking
  • Line 42-43 (OmniAccountV2.sol): Module selector constants could be moved to interface
  • Documentation: Consider adding NatSpec documentation for public module functions

✅ Conclusion

This is a well-implemented module system with excellent test coverage and clean architecture. However, the delegatecall security model requires immediate attention before production deployment. The current implementation trusts modules completely, which poses significant security risks.

Recommendation: Address the critical security concerns above before merging. The module interface standardization and safety validation are essential for secure operation.


Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants